home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / p_client.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  40.0 KB  |  1,742 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include "g_local.h"
  21. #include "m_player.h"
  22.  
  23. void SP_misc_teleporter_dest (edict_t *ent);
  24.  
  25. //
  26. // Gross, ugly, disgustuing hack section
  27. //
  28.  
  29. // this function is an ugly as hell hack to fix some map flaws
  30. //
  31. // the coop spawn spots on some maps are SNAFU.  There are coop spots
  32. // with the wrong targetname as well as spots with no name at all
  33. //
  34. // we use carnal knowledge of the maps to fix the coop spot targetnames to match
  35. // that of the nearest named single player spot
  36.  
  37. static void SP_FixCoopSpots (edict_t *self)
  38. {
  39.     edict_t    *spot;
  40.     vec3_t    d;
  41.  
  42.     spot = NULL;
  43.  
  44.     while(1)
  45.     {
  46.         spot = G_Find(spot, FOFS(classname), "info_player_start");
  47.         if (!spot)
  48.             return;
  49.         if (!spot->targetname)
  50.             continue;
  51.         VectorSubtract(self->s.origin, spot->s.origin, d);
  52.         if (VectorLength(d) < 384)
  53.         {
  54.             if ((!self->targetname) || stricmp(self->targetname, spot->targetname) != 0)
  55.             {
  56. //                gi.dprintf("FixCoopSpots changed %s at %s targetname from %s to %s\n", self->classname, vtos(self->s.origin), self->targetname, spot->targetname);
  57.                 self->targetname = spot->targetname;
  58.             }
  59.             return;
  60.         }
  61.     }
  62. }
  63.  
  64. // now if that one wasn't ugly enough for you then try this one on for size
  65. // some maps don't have any coop spots at all, so we need to create them
  66. // where they should have been
  67.  
  68. static void SP_CreateCoopSpots (edict_t *self)
  69. {
  70.     edict_t    *spot;
  71.  
  72.     if(stricmp(level.mapname, "security") == 0)
  73.     {
  74.         spot = G_Spawn();
  75.         spot->classname = "info_player_coop";
  76.         spot->s.origin[0] = 188 - 64;
  77.         spot->s.origin[1] = -164;
  78.         spot->s.origin[2] = 80;
  79.         spot->targetname = "jail3";
  80.         spot->s.angles[1] = 90;
  81.  
  82.         spot = G_Spawn();
  83.         spot->classname = "info_player_coop";
  84.         spot->s.origin[0] = 188 + 64;
  85.         spot->s.origin[1] = -164;
  86.         spot->s.origin[2] = 80;
  87.         spot->targetname = "jail3";
  88.         spot->s.angles[1] = 90;
  89.  
  90.         spot = G_Spawn();
  91.         spot->classname = "info_player_coop";
  92.         spot->s.origin[0] = 188 + 128;
  93.         spot->s.origin[1] = -164;
  94.         spot->s.origin[2] = 80;
  95.         spot->targetname = "jail3";
  96.         spot->s.angles[1] = 90;
  97.  
  98.         return;
  99.     }
  100. }
  101.  
  102.  
  103. /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
  104. The normal starting point for a level.
  105. */
  106. void SP_info_player_start(edict_t *self)
  107. {
  108.     if (!coop->value)
  109.         return;
  110.     if(stricmp(level.mapname, "security") == 0)
  111.     {
  112.         // invoke one of our gross, ugly, disgusting hacks
  113.         self->think = SP_CreateCoopSpots;
  114.         self->nextthink = level.time + FRAMETIME;
  115.     }
  116. }
  117.  
  118. /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32)
  119. potential spawning position for deathmatch games
  120. */
  121. void SP_info_player_deathmatch(edict_t *self)
  122. {
  123.     if (!deathmatch->value)
  124.     {
  125.         G_FreeEdict (self);
  126.         return;
  127.     }
  128.     SP_misc_teleporter_dest (self);
  129. }
  130.  
  131. /*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 32)
  132. potential spawning position for coop games
  133. */
  134.  
  135. void SP_info_player_coop(edict_t *self)
  136. {
  137.     if (!coop->value)
  138.     {
  139.         G_FreeEdict (self);
  140.         return;
  141.     }
  142.  
  143.     if((stricmp(level.mapname, "jail2") == 0)   ||
  144.        (stricmp(level.mapname, "jail4") == 0)   ||
  145.        (stricmp(level.mapname, "mine1") == 0)   ||
  146.        (stricmp(level.mapname, "mine2") == 0)   ||
  147.        (stricmp(level.mapname, "mine3") == 0)   ||
  148.        (stricmp(level.mapname, "mine4") == 0)   ||
  149.        (stricmp(level.mapname, "lab") == 0)     ||
  150.        (stricmp(level.mapname, "boss1") == 0)   ||
  151.        (stricmp(level.mapname, "fact3") == 0)   ||
  152.        (stricmp(level.mapname, "biggun") == 0)  ||
  153.        (stricmp(level.mapname, "space") == 0)   ||
  154.        (stricmp(level.mapname, "command") == 0) ||
  155.        (stricmp(level.mapname, "power2") == 0) ||
  156.        (stricmp(level.mapname, "strike") == 0))
  157.     {
  158.         // invoke one of our gross, ugly, disgusting hacks
  159.         self->think = SP_FixCoopSpots;
  160.         self->nextthink = level.time + FRAMETIME;
  161.     }
  162. }
  163.  
  164.  
  165. /*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
  166. The deathmatch intermission point will be at one of these
  167. Use 'angles' instead of 'angle', so you can set pitch or roll as well as yaw.  'pitch yaw roll'
  168. */
  169. void SP_info_player_intermission(void)
  170. {
  171. }
  172.  
  173.  
  174. //=======================================================================
  175.  
  176.  
  177. void player_pain (edict_t *self, edict_t *other, float kick, int damage)
  178. {
  179.     // player pain is handled at the end of the frame in P_DamageFeedback
  180. }
  181.  
  182.  
  183. qboolean IsFemale (edict_t *ent)
  184. {
  185.     char        *info;
  186.  
  187.     if (!ent->client)
  188.         return false;
  189.  
  190.     info = Info_ValueForKey (ent->client->pers.userinfo, "skin");
  191.     if (info[0] == 'f' || info[0] == 'F')
  192.         return true;
  193.     return false;
  194. }
  195.  
  196.  
  197. void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
  198. {
  199.     int            mod;
  200.     char        *message;
  201.     char        *message2;
  202.     qboolean    ff;
  203.  
  204.  
  205.     if (coop->value && attacker->client)
  206.         meansOfDeath |= MOD_FRIENDLY_FIRE;
  207.  
  208.     if (deathmatch->value || coop->value)
  209.     {
  210.         ff = meansOfDeath & MOD_FRIENDLY_FIRE;
  211.         mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
  212.         message = NULL;
  213.         message2 = "";
  214.  
  215.         switch (mod)
  216.         {
  217.         case MOD_SUICIDE:
  218.             message = "suicides";
  219.             break;
  220.         case MOD_FALLING:
  221.             message = "cratered";
  222.             break;
  223.         case MOD_CRUSH:
  224.             message = "was squished";
  225.             break;
  226.         case MOD_WATER:
  227.             message = "sank like a rock";
  228.             break;
  229.         case MOD_SLIME:
  230.             message = "melted";
  231.             break;
  232.         case MOD_LAVA:
  233.             message = "does a back flip into the lava";
  234.             break;
  235.         case MOD_EXPLOSIVE:
  236.         case MOD_BARREL:
  237.             message = "blew up";
  238.             break;
  239.         case MOD_EXIT:
  240.             message = "found a way out";
  241.             break;
  242.         case MOD_TARGET_LASER:
  243.             message = "saw the light";
  244.             break;
  245.         case MOD_TARGET_BLASTER:
  246.             message = "got blasted";
  247.             break;
  248.         case MOD_BOMB:
  249.         case MOD_SPLASH:
  250.         case MOD_TRIGGER_HURT:
  251.             message = "was in the wrong place";
  252.             break;
  253.         }
  254.         if (attacker == self)
  255.         {
  256.             switch (mod)
  257.             {
  258.             case MOD_HELD_GRENADE:
  259.                 message = "tried to put the pin back in";
  260.                 break;
  261.             case MOD_HG_SPLASH:
  262.             case MOD_G_SPLASH:
  263.                 if (IsFemale(self))
  264.                     message = "tripped on her own grenade";
  265.                 else
  266.                     message = "tripped on his own grenade";
  267.                 break;
  268.             case MOD_R_SPLASH:
  269.                 if (IsFemale(self))
  270.                     message = "blew herself up";
  271.                 else
  272.                     message = "blew himself up";
  273.                 break;
  274.             case MOD_BFG_BLAST:
  275.                 message = "should have used a smaller gun";
  276.                 break;
  277.             default:
  278.                 if (IsFemale(self))
  279.                     message = "killed herself";
  280.                 else
  281.                     message = "killed himself";
  282.                 break;
  283.             }
  284.         }
  285.         if (message)
  286.         {
  287.             gi.bprintf (PRINT_MEDIUM, "%s %s.\n", self->client->pers.netname, message);
  288.             if (deathmatch->value)
  289.             self->client->resp.score--;
  290.             self->enemy = NULL;
  291.             return;
  292.         }
  293.  
  294.         self->enemy = attacker;
  295.         if (attacker && attacker->client)
  296.         {
  297.             switch (mod)
  298.             {
  299.             case MOD_BLASTER:
  300.                 message = "was blasted by";
  301.                 break;
  302.             case MOD_SHOTGUN:
  303.                 message = "was gunned down by";
  304.                 break;
  305.             case MOD_SSHOTGUN:
  306.                 message = "was blown away by";
  307.                 message2 = "'s super shotgun";
  308.                 break;
  309.             case MOD_MACHINEGUN:
  310.                 message = "was machinegunned by";
  311.                 break;
  312.             case MOD_CHAINGUN:
  313.                 message = "was cut in half by";
  314.                 message2 = "'s chaingun";
  315.                 break;
  316.             case MOD_GRENADE:
  317.                 message = "was popped by";
  318.                 message2 = "'s grenade";
  319.                 break;
  320.             case MOD_G_SPLASH:
  321.                 message = "was shredded by";
  322.                 message2 = "'s shrapnel";
  323.                 break;
  324.             case MOD_ROCKET:
  325.                 message = "ate";
  326.                 message2 = "'s rocket";
  327.                 break;
  328.             case MOD_R_SPLASH:
  329.                 message = "almost dodged";
  330.                 message2 = "'s rocket";
  331.                 break;
  332.             case MOD_HYPERBLASTER:
  333.                 message = "was melted by";
  334.                 message2 = "'s hyperblaster";
  335.                 break;
  336.             case MOD_RAILGUN:
  337.                 message = "was railed by";
  338.                 break;
  339.             case MOD_BFG_LASER:
  340.                 message = "saw the pretty lights from";
  341.                 message2 = "'s BFG";
  342.                 break;
  343.             case MOD_BFG_BLAST:
  344.                 message = "was disintegrated by";
  345.                 message2 = "'s BFG blast";
  346.                 break;
  347.             case MOD_BFG_EFFECT:
  348.                 message = "couldn't hide from";
  349.                 message2 = "'s BFG";
  350.                 break;
  351.             case MOD_HANDGRENADE:
  352.                 message = "caught";
  353.                 message2 = "'s handgrenade";
  354.                 break;
  355.             case MOD_HG_SPLASH:
  356.                 message = "didn't see";
  357.                 message2 = "'s handgrenade";
  358.                 break;
  359.             case MOD_HELD_GRENADE:
  360.                 message = "feels";
  361.                 message2 = "'s pain";
  362.                 break;
  363.             case MOD_TELEFRAG:
  364.                 message = "tried to invade";
  365.                 message2 = "'s personal space";
  366.                 break;
  367. //ZOID
  368.             case MOD_GRAPPLE:
  369.                 message = "was caught by";
  370.                 message2 = "'s grapple";
  371.                 break;
  372. //ZOID
  373.  
  374.             }
  375.             if (message)
  376.             {
  377.                 gi.bprintf (PRINT_MEDIUM,"%s %s %s%s\n", self->client->pers.netname, message, attacker->client->pers.netname, message2);
  378.                 if (deathmatch->value)
  379.                 {
  380.                     if (ff)
  381.                         attacker->client->resp.score--;
  382.                     else
  383.                         attacker->client->resp.score++;
  384.                 }
  385.                 return;
  386.             }
  387.         }
  388.     }
  389.  
  390.     gi.bprintf (PRINT_MEDIUM,"%s died.\n", self->client->pers.netname);
  391.     if (deathmatch->value)
  392.     self->client->resp.score--;
  393. }
  394.  
  395.  
  396. void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
  397.  
  398. void TossClientWeapon (edict_t *self)
  399. {
  400.     gitem_t        *item;
  401.     edict_t        *drop;
  402.     qboolean    quad;
  403.     float        spread;
  404.  
  405.     if (!deathmatch->value)
  406.         return;
  407.  
  408.     item = self->client->pers.weapon;
  409.     if (! self->client->pers.inventory[self->client->ammo_index] )
  410.         item = NULL;
  411.     if (item && (strcmp (item->pickup_name, "Blaster") == 0))
  412.         item = NULL;
  413.  
  414.     if (!((int)(dmflags->value) & DF_QUAD_DROP))
  415.         quad = false;
  416.     else
  417.         quad = (self->client->quad_framenum > (level.framenum + 10));
  418.  
  419.     if (item && quad)
  420.         spread = 22.5;
  421.     else
  422.         spread = 0.0;
  423.  
  424.     if (item)
  425.     {
  426.         self->client->v_angle[YAW] -= spread;
  427.         drop = Drop_Item (self, item);
  428.         self->client->v_angle[YAW] += spread;
  429.         drop->spawnflags = DROPPED_PLAYER_ITEM;
  430.     }
  431.  
  432.     if (quad)
  433.     {
  434.         self->client->v_angle[YAW] += spread;
  435.         drop = Drop_Item (self, FindItemByClassname ("item_quad"));
  436.         self->client->v_angle[YAW] -= spread;
  437.         drop->spawnflags |= DROPPED_PLAYER_ITEM;
  438.  
  439.         drop->touch = Touch_Item;
  440.         drop->nextthink = level.time + (self->client->quad_framenum - level.framenum) * FRAMETIME;
  441.         drop->think = G_FreeEdict;
  442.     }
  443. }
  444.  
  445.  
  446. /*
  447. ==================
  448. LookAtKiller
  449. ==================
  450. */
  451. void LookAtKiller (edict_t *self, edict_t *inflictor, edict_t *attacker)
  452. {
  453.     vec3_t        dir;
  454.  
  455.     if (attacker && attacker != world && attacker != self)
  456.     {
  457.         VectorSubtract (attacker->s.origin, self->s.origin, dir);
  458.     }
  459.     else if (inflictor && inflictor != world && inflictor != self)
  460.     {
  461.         VectorSubtract (inflictor->s.origin, self->s.origin, dir);
  462.     }
  463.     else
  464.     {
  465.         self->client->killer_yaw = self->s.angles[YAW];
  466.         return;
  467.     }
  468.  
  469.     if (dir[0])
  470.         self->client->killer_yaw = 180/M_PI*atan2(dir[1], dir[0]);
  471.     else {
  472.         self->client->killer_yaw = 0;
  473.         if (dir[1] > 0)
  474.             self->client->killer_yaw = 90;
  475.         else if (dir[1] < 0)
  476.             self->client->killer_yaw = -90;
  477.     }
  478.     if (self->client->killer_yaw < 0)
  479.         self->client->killer_yaw += 360;
  480. }
  481.  
  482. /*
  483. ==================
  484. player_die
  485. ==================
  486. */
  487. void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  488. {
  489.     int        n;
  490.  
  491.     VectorClear (self->avelocity);
  492.  
  493.     self->takedamage = DAMAGE_YES;
  494.     self->movetype = MOVETYPE_TOSS;
  495.  
  496.     self->s.modelindex2 = 0;    // remove linked weapon model
  497. //ZOID
  498.     self->s.modelindex3 = 0;    // remove linked ctf flag
  499. //ZOID
  500.  
  501.     self->s.angles[0] = 0;
  502.     self->s.angles[2] = 0;
  503.  
  504.     self->s.sound = 0;
  505.     self->client->weapon_sound = 0;
  506.  
  507.     self->maxs[2] = -8;
  508.  
  509. //    self->solid = SOLID_NOT;
  510.     self->svflags |= SVF_DEADMONSTER;
  511.  
  512.     if (!self->deadflag)
  513.     {
  514.         self->client->respawn_time = level.time + 1.0;
  515.         LookAtKiller (self, inflictor, attacker);
  516.         self->client->ps.pmove.pm_type = PM_DEAD;
  517.         ClientObituary (self, inflictor, attacker);
  518. //ZOID
  519.         // if at start and same team, clear
  520.         if (ctf->value && meansOfDeath == MOD_TELEFRAG &&
  521.             self->client->resp.ctf_state < 2 &&
  522.             self->client->resp.ctf_team == attacker->client->resp.ctf_team) {
  523.             attacker->client->resp.score--;
  524.             self->client->resp.ctf_state = 0;
  525.         }
  526.  
  527.         CTFFragBonuses(self, inflictor, attacker);
  528. //ZOID
  529.         TossClientWeapon (self);
  530. //ZOID
  531.         CTFPlayerResetGrapple(self);
  532.         CTFDeadDropFlag(self);
  533.         CTFDeadDropTech(self);
  534. //ZOID
  535.         if (deathmatch->value && !self->client->showscores)
  536.             Cmd_Help_f (self);        // show scores
  537.     }
  538.  
  539.     // remove powerups
  540.     self->client->quad_framenum = 0;
  541.     self->client->invincible_framenum = 0;
  542.     self->client->breather_framenum = 0;
  543.     self->client->enviro_framenum = 0;
  544.     self->flags &= ~FL_POWER_ARMOR;
  545.  
  546.     // clear inventory
  547.     memset(self->client->pers.inventory, 0, sizeof(self->client->pers.inventory));
  548.  
  549.     if (self->health < -40)
  550.     {    // gib
  551.         gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  552.         for (n= 0; n < 4; n++)
  553.             ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  554.         ThrowClientHead (self, damage);
  555. //ZOID
  556.         self->client->anim_priority = ANIM_DEATH;
  557.         self->client->anim_end = 0;
  558. //ZOID
  559.         self->takedamage = DAMAGE_NO;
  560.     }
  561.     else
  562.     {    // normal death
  563.         if (!self->deadflag)
  564.         {
  565.             static int i;
  566.  
  567.             i = (i+1)%3;
  568.             // start a death animation
  569.             self->client->anim_priority = ANIM_DEATH;
  570.             if (self->client->ps.pmove.pm_flags & PMF_DUCKED)
  571.             {
  572.                 self->s.frame = FRAME_crdeath1-1;
  573.                 self->client->anim_end = FRAME_crdeath5;
  574.             }
  575.             else switch (i)
  576.             {
  577.             case 0:
  578.                 self->s.frame = FRAME_death101-1;
  579.                 self->client->anim_end = FRAME_death106;
  580.                 break;
  581.             case 1:
  582.                 self->s.frame = FRAME_death201-1;
  583.                 self->client->anim_end = FRAME_death206;
  584.                 break;
  585.             case 2:
  586.                 self->s.frame = FRAME_death301-1;
  587.                 self->client->anim_end = FRAME_death308;
  588.                 break;
  589.             }
  590.             gi.sound (self, CHAN_VOICE, gi.soundindex(va("*death%i.wav", (rand()%4)+1)), 1, ATTN_NORM, 0);
  591.         }
  592.     }
  593.  
  594.     self->deadflag = DEAD_DEAD;
  595.  
  596.     gi.linkentity (self);
  597. }
  598.  
  599. //=======================================================================
  600.  
  601. /*
  602. ==============
  603. InitClientPersistant
  604.  
  605. This is only called when the game first initializes in single player,
  606. but is called after each death and level change in deathmatch
  607. ==============
  608. */
  609. void InitClientPersistant (gclient_t *client)
  610. {
  611.     gitem_t        *item;
  612.  
  613.     memset (&client->pers, 0, sizeof(client->pers));
  614.  
  615.     item = FindItem("Blaster");
  616.     client->pers.selected_item = ITEM_INDEX(item);
  617.     client->pers.inventory[client->pers.selected_item] = 1;
  618.  
  619.     client->pers.weapon = item;
  620. //ZOID
  621.     client->pers.lastweapon = item;
  622. //ZOID
  623.  
  624. //ZOID
  625.     item = FindItem("Grapple");
  626.     client->pers.inventory[ITEM_INDEX(item)] = 1;
  627. //ZOID
  628.  
  629.     client->pers.health            = 100;
  630.     client->pers.max_health        = 100;
  631.  
  632.     client->pers.max_bullets    = 200;
  633.     client->pers.max_shells        = 100;
  634.     client->pers.max_rockets    = 50;
  635.     client->pers.max_grenades    = 50;
  636.     client->pers.max_cells        = 200;
  637.     client->pers.max_slugs        = 50;
  638.  
  639.     client->pers.connected = true;
  640. }
  641.  
  642.  
  643. void InitClientResp (gclient_t *client)
  644. {
  645. //ZOID
  646.     int ctf_team = client->resp.ctf_team;
  647.     qboolean id_state = client->resp.id_state;
  648. //ZOID
  649.  
  650.     memset (&client->resp, 0, sizeof(client->resp));
  651.     
  652. //ZOID
  653.     client->resp.ctf_team = ctf_team;
  654.     client->resp.id_state = id_state;
  655. //ZOID
  656.  
  657.     client->resp.enterframe = level.framenum;
  658.     client->resp.coop_respawn = client->pers;
  659.  
  660. //ZOID
  661.     if (ctf->value && client->resp.ctf_team < CTF_TEAM1)
  662.         CTFAssignTeam(client);
  663. //ZOID
  664. }
  665.  
  666. /*
  667. ==================
  668. SaveClientData
  669.  
  670. Some information that should be persistant, like health, 
  671. is still stored in the edict structure, so it needs to
  672. be mirrored out to the client structure before all the
  673. edicts are wiped.
  674. ==================
  675. */
  676. void SaveClientData (void)
  677. {
  678.     int        i;
  679.     edict_t    *ent;
  680.  
  681.     for (i=0 ; i<game.maxclients ; i++)
  682.     {
  683.         ent = &g_edicts[1+i];
  684.         if (!ent->inuse)
  685.             continue;
  686.         game.clients[i].pers.health = ent->health;
  687.         game.clients[i].pers.max_health = ent->max_health;
  688.         game.clients[i].pers.savedFlags = (ent->flags & (FL_GODMODE|FL_NOTARGET|FL_POWER_ARMOR));
  689.         if (coop->value)
  690.             game.clients[i].pers.score = ent->client->resp.score;
  691.     }
  692. }
  693.  
  694. void FetchClientEntData (edict_t *ent)
  695. {
  696.     ent->health = ent->client->pers.health;
  697.     ent->max_health = ent->client->pers.max_health;
  698.     ent->flags |= ent->client->pers.savedFlags;
  699.     if (coop->value)
  700.         ent->client->resp.score = ent->client->pers.score;
  701. }
  702.  
  703.  
  704.  
  705. /*
  706. =======================================================================
  707.  
  708.   SelectSpawnPoint
  709.  
  710. =======================================================================
  711. */
  712.  
  713. /*
  714. ================
  715. PlayersRangeFromSpot
  716.  
  717. Returns the distance to the nearest player from the given spot
  718. ================
  719. */
  720. float    PlayersRangeFromSpot (edict_t *spot)
  721. {
  722.     edict_t    *player;
  723.     float    bestplayerdistance;
  724.     vec3_t    v;
  725.     int        n;
  726.     float    playerdistance;
  727.  
  728.  
  729.     bestplayerdistance = 9999999;
  730.  
  731.     for (n = 1; n <= maxclients->value; n++)
  732.     {
  733.         player = &g_edicts[n];
  734.  
  735.         if (!player->inuse)
  736.             continue;
  737.  
  738.         if (player->health <= 0)
  739.             continue;
  740.  
  741.         VectorSubtract (spot->s.origin, player->s.origin, v);
  742.         playerdistance = VectorLength (v);
  743.  
  744.         if (playerdistance < bestplayerdistance)
  745.             bestplayerdistance = playerdistance;
  746.     }
  747.  
  748.     return bestplayerdistance;
  749. }
  750.  
  751. /*
  752. ================
  753. SelectRandomDeathmatchSpawnPoint
  754.  
  755. go to a random point, but NOT the two points closest
  756. to other players
  757. ================
  758. */
  759. edict_t *SelectRandomDeathmatchSpawnPoint (void)
  760. {
  761.     edict_t    *spot, *spot1, *spot2;
  762.     int        count = 0;
  763.     int        selection;
  764.     float    range, range1, range2;
  765.  
  766.     spot = NULL;
  767.     range1 = range2 = 99999;
  768.     spot1 = spot2 = NULL;
  769.  
  770.     while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
  771.     {
  772.         count++;
  773.         range = PlayersRangeFromSpot(spot);
  774.         if (range < range1)
  775.         {
  776.             range1 = range;
  777.             spot1 = spot;
  778.         }
  779.         else if (range < range2)
  780.         {
  781.             range2 = range;
  782.             spot2 = spot;
  783.         }
  784.     }
  785.  
  786.     if (!count)
  787.         return NULL;
  788.  
  789.     if (count <= 2)
  790.     {
  791.         spot1 = spot2 = NULL;
  792.     }
  793.     else
  794.         count -= 2;
  795.  
  796.     selection = rand() % count;
  797.  
  798.     spot = NULL;
  799.     do
  800.     {
  801.         spot = G_Find (spot, FOFS(classname), "info_player_deathmatch");
  802.         if (spot == spot1 || spot == spot2)
  803.             selection++;
  804.     } while(selection--);
  805.  
  806.     return spot;
  807. }
  808.  
  809. /*
  810. ================
  811. SelectFarthestDeathmatchSpawnPoint
  812.  
  813. ================
  814. */
  815. edict_t *SelectFarthestDeathmatchSpawnPoint (void)
  816. {
  817.     edict_t    *bestspot;
  818.     float    bestdistance, bestplayerdistance;
  819.     edict_t    *spot;
  820.  
  821.  
  822.     spot = NULL;
  823.     bestspot = NULL;
  824.     bestdistance = 0;
  825.     while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
  826.     {
  827.         bestplayerdistance = PlayersRangeFromSpot (spot);
  828.  
  829.         if (bestplayerdistance > bestdistance)
  830.         {
  831.             bestspot = spot;
  832.             bestdistance = bestplayerdistance;
  833.         }
  834.     }
  835.  
  836.     if (bestspot)
  837.     {
  838.         return bestspot;
  839.     }
  840.  
  841.     // if there is a player just spawned on each and every start spot
  842.     // we have no choice to turn one into a telefrag meltdown
  843.     spot = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
  844.  
  845.     return spot;
  846. }
  847.  
  848. edict_t *SelectDeathmatchSpawnPoint (void)
  849. {
  850.     if ( (int)(dmflags->value) & DF_SPAWN_FARTHEST)
  851.         return SelectFarthestDeathmatchSpawnPoint ();
  852.     else
  853.         return SelectRandomDeathmatchSpawnPoint ();
  854. }
  855.  
  856.  
  857. edict_t *SelectCoopSpawnPoint (edict_t *ent)
  858. {
  859.     int        index;
  860.     edict_t    *spot = NULL;
  861.     char    *target;
  862.  
  863.     index = ent->client - game.clients;
  864.  
  865.     // player 0 starts in normal player spawn point
  866.     if (!index)
  867.         return NULL;
  868.  
  869.     spot = NULL;
  870.  
  871.     // assume there are four coop spots at each spawnpoint
  872.     while (1)
  873.     {
  874.         spot = G_Find (spot, FOFS(classname), "info_player_coop");
  875.         if (!spot)
  876.             return NULL;    // we didn't have enough...
  877.  
  878.         target = spot->targetname;
  879.         if (!target)
  880.             target = "";
  881.         if ( Q_stricmp(game.spawnpoint, target) == 0 )
  882.         {    // this is a coop spawn point for one of the clients here
  883.             index--;
  884.             if (!index)
  885.                 return spot;        // this is it
  886.         }
  887.     }
  888.  
  889.  
  890.     return spot;
  891. }
  892.  
  893.  
  894. /*
  895. ===========
  896. SelectSpawnPoint
  897.  
  898. Chooses a player start, deathmatch start, coop start, etc
  899. ============
  900. */
  901. void    SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles)
  902. {
  903.     edict_t    *spot = NULL;
  904.  
  905.     if (deathmatch->value)
  906. //ZOID
  907.         if (ctf->value)
  908.             spot = SelectCTFSpawnPoint(ent);
  909.         else
  910. //ZOID
  911.             spot = SelectDeathmatchSpawnPoint ();
  912.     else if (coop->value)
  913.         spot = SelectCoopSpawnPoint (ent);
  914.  
  915.     // find a single player start spot
  916.     if (!spot)
  917.     {
  918.         while ((spot = G_Find (spot, FOFS(classname), "info_player_start")) != NULL)
  919.         {
  920.             if (!game.spawnpoint[0] && !spot->targetname)
  921.                 break;
  922.  
  923.             if (!game.spawnpoint[0] || !spot->targetname)
  924.                 continue;
  925.  
  926.             if (Q_stricmp(game.spawnpoint, spot->targetname) == 0)
  927.                 break;
  928.         }
  929.  
  930.         if (!spot)
  931.         {
  932.             if (!game.spawnpoint[0])
  933.             {    // there wasn't a spawnpoint without a target, so use any
  934.                 spot = G_Find (spot, FOFS(classname), "info_player_start");
  935.             }
  936.             if (!spot)
  937.                 gi.error ("Couldn't find spawn point %s\n", game.spawnpoint);
  938.         }
  939.     }
  940.  
  941.     VectorCopy (spot->s.origin, origin);
  942.     origin[2] += 9;
  943.     VectorCopy (spot->s.angles, angles);
  944. }
  945.  
  946. //======================================================================
  947.  
  948.  
  949. void InitBodyQue (void)
  950. {
  951.     int        i;
  952.     edict_t    *ent;
  953.  
  954.     level.body_que = 0;
  955.     for (i=0; i<BODY_QUEUE_SIZE ; i++)
  956.     {
  957.         ent = G_Spawn();
  958.         ent->classname = "bodyque";
  959.     }
  960. }
  961.  
  962. void body_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  963. {
  964.     int    n;
  965.  
  966.     if (self->health < -40)
  967.     {
  968.         gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  969.         for (n= 0; n < 4; n++)
  970.             ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  971.         self->s.origin[2] -= 48;
  972.         ThrowClientHead (self, damage);
  973.         self->takedamage = DAMAGE_NO;
  974.     }
  975. }
  976.  
  977. void CopyToBodyQue (edict_t *ent)
  978. {
  979.     edict_t        *body;
  980.  
  981.  
  982.     // grab a body que and cycle to the next one
  983.     body = &g_edicts[(int)maxclients->value + level.body_que + 1];
  984.     level.body_que = (level.body_que + 1) % BODY_QUEUE_SIZE;
  985.  
  986.     // FIXME: send an effect on the removed body
  987.  
  988.     gi.unlinkentity (ent);
  989.  
  990.     gi.unlinkentity (body);
  991.     body->s = ent->s;
  992.     body->s.number = body - g_edicts;
  993.  
  994.     body->svflags = ent->svflags;
  995.     VectorCopy (ent->mins, body->mins);
  996.     VectorCopy (ent->maxs, body->maxs);
  997.     VectorCopy (ent->absmin, body->absmin);
  998.     VectorCopy (ent->absmax, body->absmax);
  999.     VectorCopy (ent->size, body->size);
  1000.     body->solid = ent->solid;
  1001.     body->clipmask = ent->clipmask;
  1002.     body->owner = ent->owner;
  1003.     body->movetype = ent->movetype;
  1004.  
  1005.     body->die = body_die;
  1006.     body->takedamage = DAMAGE_YES;
  1007.  
  1008.     gi.linkentity (body);
  1009. }
  1010.  
  1011.  
  1012. void respawn (edict_t *self)
  1013. {
  1014.     if (deathmatch->value || coop->value)
  1015.     {
  1016.         if (self->movetype != MOVETYPE_NOCLIP)
  1017.             CopyToBodyQue (self);
  1018.         self->svflags &= ~SVF_NOCLIENT;
  1019.         PutClientInServer (self);
  1020.  
  1021.         // add a teleportation effect
  1022.         self->s.event = EV_PLAYER_TELEPORT;
  1023.  
  1024.         // hold in place briefly
  1025.         self->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
  1026.         self->client->ps.pmove.pm_time = 14;
  1027.  
  1028.         self->client->respawn_time = level.time;
  1029.  
  1030.         return;
  1031.     }
  1032.  
  1033.     // restart the entire server
  1034.     gi.AddCommandString ("menu_loadgame\n");
  1035. }
  1036.  
  1037. //==============================================================
  1038.  
  1039.  
  1040. /*
  1041. ===========
  1042. PutClientInServer
  1043.  
  1044. Called when a player connects to a server or respawns in
  1045. a deathmatch.
  1046. ============
  1047. */
  1048. void PutClientInServer (edict_t *ent)
  1049. {
  1050.     vec3_t    mins = {-16, -16, -24};
  1051.     vec3_t    maxs = {16, 16, 32};
  1052.     int        index;
  1053.     vec3_t    spawn_origin, spawn_angles;
  1054.     gclient_t    *client;
  1055.     int        i;
  1056.     client_persistant_t    saved;
  1057.     client_respawn_t    resp;
  1058.  
  1059.     // find a spawn point
  1060.     // do it before setting health back up, so farthest
  1061.     // ranging doesn't count this client
  1062.     SelectSpawnPoint (ent, spawn_origin, spawn_angles);
  1063.  
  1064.     index = ent-g_edicts-1;
  1065.     client = ent->client;
  1066.  
  1067.     // deathmatch wipes most client data every spawn
  1068.     if (deathmatch->value)
  1069.     {
  1070.         char        userinfo[MAX_INFO_STRING];
  1071.  
  1072.         resp = client->resp;
  1073.         memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
  1074.         InitClientPersistant (client);
  1075.         ClientUserinfoChanged (ent, userinfo);
  1076.     }
  1077.     else if (coop->value)
  1078.     {
  1079.         int            n;
  1080.         char        userinfo[MAX_INFO_STRING];
  1081.  
  1082.         resp = client->resp;
  1083.         memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
  1084.         // this is kind of ugly, but it's how we want to handle keys in coop
  1085.         for (n = 0; n < MAX_ITEMS; n++)
  1086.         {
  1087.             if (itemlist[n].flags & IT_KEY)
  1088.                 resp.coop_respawn.inventory[n] = client->pers.inventory[n];
  1089.         }
  1090.         client->pers = resp.coop_respawn;
  1091.         ClientUserinfoChanged (ent, userinfo);
  1092.         if (resp.score > client->pers.score)
  1093.             client->pers.score = resp.score;
  1094.     }
  1095.     else
  1096.     {
  1097.         memset (&resp, 0, sizeof(resp));
  1098.     }
  1099.  
  1100.     // clear everything but the persistant data
  1101.     saved = client->pers;
  1102.     memset (client, 0, sizeof(*client));
  1103.     client->pers = saved;
  1104.     if (client->pers.health <= 0)
  1105.         InitClientPersistant(client);
  1106.     client->resp = resp;
  1107.  
  1108.     // copy some data from the client to the entity
  1109.     FetchClientEntData (ent);
  1110.  
  1111.     // clear entity values
  1112.     ent->groundentity = NULL;
  1113.     ent->client = &game.clients[index];
  1114.     ent->takedamage = DAMAGE_AIM;
  1115.     ent->movetype = MOVETYPE_WALK;
  1116.     ent->viewheight = 22;
  1117.     ent->inuse = true;
  1118.     ent->classname = "player";
  1119.     ent->mass = 200;
  1120.     ent->solid = SOLID_BBOX;
  1121.     ent->deadflag = DEAD_NO;
  1122.     ent->air_finished = level.time + 12;
  1123.     ent->clipmask = MASK_PLAYERSOLID;
  1124.     ent->model = "players/male/tris.md2";
  1125.     ent->pain = player_pain;
  1126.     ent->die = player_die;
  1127.     ent->waterlevel = 0;
  1128.     ent->watertype = 0;
  1129.     ent->flags &= ~FL_NO_KNOCKBACK;
  1130.     ent->svflags &= ~SVF_DEADMONSTER;
  1131.  
  1132.     VectorCopy (mins, ent->mins);
  1133.     VectorCopy (maxs, ent->maxs);
  1134.     VectorClear (ent->velocity);
  1135.  
  1136.     // clear playerstate values
  1137.     memset (&ent->client->ps, 0, sizeof(client->ps));
  1138.  
  1139.     client->ps.pmove.origin[0] = spawn_origin[0]*8;
  1140.     client->ps.pmove.origin[1] = spawn_origin[1]*8;
  1141.     client->ps.pmove.origin[2] = spawn_origin[2]*8;
  1142. //ZOID
  1143.     client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
  1144. //ZOID
  1145.  
  1146.     if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
  1147.     {
  1148.         client->ps.fov = 90;
  1149.     }
  1150.     else
  1151.     {
  1152.         client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov"));
  1153.         if (client->ps.fov < 1)
  1154.             client->ps.fov = 90;
  1155.         else if (client->ps.fov > 160)
  1156.             client->ps.fov = 160;
  1157.     }
  1158.  
  1159.     client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model);
  1160.  
  1161.     // clear entity state values
  1162.     ent->s.effects = 0;
  1163.     ent->s.skinnum = ent - g_edicts - 1;
  1164.     ent->s.modelindex = 255;        // will use the skin specified model
  1165.     ent->s.modelindex2 = 255;        // custom gun model
  1166.     // sknum is player num and weapon number
  1167.     // weapon number will be added in changeweapon
  1168.     ent->s.skinnum = ent - g_edicts - 1;
  1169.  
  1170.     ent->s.frame = 0;
  1171.     VectorCopy (spawn_origin, ent->s.origin);
  1172.     ent->s.origin[2] += 1;    // make sure off ground
  1173.     VectorCopy (ent->s.origin, ent->s.old_origin);
  1174.  
  1175.     // set the delta angle
  1176.     for (i=0 ; i<3 ; i++)
  1177.         client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]);
  1178.  
  1179.     ent->s.angles[PITCH] = 0;
  1180.     ent->s.angles[YAW] = spawn_angles[YAW];
  1181.     ent->s.angles[ROLL] = 0;
  1182.     VectorCopy (ent->s.angles, client->ps.viewangles);
  1183.     VectorCopy (ent->s.angles, client->v_angle);
  1184.  
  1185. //ZOID
  1186.     if (CTFStartClient(ent))
  1187.         return;
  1188. //ZOID
  1189.  
  1190.     if (!KillBox (ent))
  1191.     {    // could't spawn in?
  1192.     }
  1193.  
  1194.     gi.linkentity (ent);
  1195.  
  1196.     // force the current weapon up
  1197.     client->newweapon = client->pers.weapon;
  1198.     ChangeWeapon (ent);
  1199. }
  1200.  
  1201. /*
  1202. =====================
  1203. ClientBeginDeathmatch
  1204.  
  1205. A client has just connected to the server in 
  1206. deathmatch mode, so clear everything out before starting them.
  1207. =====================
  1208. */
  1209. void ClientBeginDeathmatch (edict_t *ent)
  1210. {
  1211.     G_InitEdict (ent);
  1212.  
  1213.     InitClientResp (ent->client);
  1214.  
  1215.     // locate ent at a spawn point
  1216.     PutClientInServer (ent);
  1217.  
  1218.     if (level.intermissiontime)
  1219.     {
  1220.         MoveClientToIntermission (ent);
  1221.     }
  1222.     else
  1223.     {
  1224.         // send effect
  1225.         gi.WriteByte (svc_muzzleflash);
  1226.         gi.WriteShort (ent-g_edicts);
  1227.         gi.WriteByte (MZ_LOGIN);
  1228.         gi.multicast (ent->s.origin, MULTICAST_PVS);
  1229.     }
  1230.  
  1231.     gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
  1232.  
  1233.     // make sure all view stuff is valid
  1234.     ClientEndServerFrame (ent);
  1235. }
  1236.  
  1237.  
  1238. /*
  1239. ===========
  1240. ClientBegin
  1241.  
  1242. called when a client has finished connecting, and is ready
  1243. to be placed into the game.  This will happen every level load.
  1244. ============
  1245. */
  1246. void ClientBegin (edict_t *ent)
  1247. {
  1248.     int        i;
  1249.  
  1250.     ent->client = game.clients + (ent - g_edicts - 1);
  1251.  
  1252.     if (deathmatch->value)
  1253.     {
  1254.         ClientBeginDeathmatch (ent);
  1255.         return;
  1256.     }
  1257.  
  1258.     // if there is already a body waiting for us (a loadgame), just
  1259.     // take it, otherwise spawn one from scratch
  1260.     if (ent->inuse == true)
  1261.     {
  1262.         // the client has cleared the client side viewangles upon
  1263.         // connecting to the server, which is different than the
  1264.         // state when the game is saved, so we need to compensate
  1265.         // with deltaangles
  1266.         for (i=0 ; i<3 ; i++)
  1267.             ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->ps.viewangles[i]);
  1268.     }
  1269.     else
  1270.     {
  1271.         // a spawn point will completely reinitialize the entity
  1272.         // except for the persistant data that was initialized at
  1273.         // ClientConnect() time
  1274.         G_InitEdict (ent);
  1275.         ent->classname = "player";
  1276.         InitClientResp (ent->client);
  1277.         PutClientInServer (ent);
  1278.     }
  1279.  
  1280.     if (level.intermissiontime)
  1281.     {
  1282.         MoveClientToIntermission (ent);
  1283.     }
  1284.     else
  1285.     {
  1286.         // send effect if in a multiplayer game
  1287.         if (game.maxclients > 1)
  1288.         {
  1289.             gi.WriteByte (svc_muzzleflash);
  1290.             gi.WriteShort (ent-g_edicts);
  1291.             gi.WriteByte (MZ_LOGIN);
  1292.             gi.multicast (ent->s.origin, MULTICAST_PVS);
  1293.  
  1294.             gi.bprintf (PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname);
  1295.         }
  1296.     }
  1297.  
  1298.     // make sure all view stuff is valid
  1299.     ClientEndServerFrame (ent);
  1300. }
  1301.  
  1302. /*
  1303. ===========
  1304. ClientUserInfoChanged
  1305.  
  1306. called whenever the player updates a userinfo variable.
  1307.  
  1308. The game can override any of the settings in place
  1309. (forcing skins or names, etc) before copying it off.
  1310. ============
  1311. */
  1312. void ClientUserinfoChanged (edict_t *ent, char *userinfo)
  1313. {
  1314.     char    *s;
  1315.     int        playernum;
  1316.  
  1317.     // check for malformed or illegal info strings
  1318.     if (!Info_Validate(userinfo))
  1319.     {
  1320.         strcpy (userinfo, "\\name\\badinfo\\skin\\male/grunt");
  1321.     }
  1322.  
  1323.     // set name
  1324.     s = Info_ValueForKey (userinfo, "name");
  1325.     strncpy (ent->client->pers.netname, s, sizeof(ent->client->pers.netname)-1);
  1326.  
  1327.     // set skin
  1328.     s = Info_ValueForKey (userinfo, "skin");
  1329.  
  1330.     playernum = ent-g_edicts-1;
  1331.  
  1332.     // combine name and skin into a configstring
  1333. //ZOID
  1334.     if (ctf->value)
  1335.         CTFAssignSkin(ent, s);
  1336.     else
  1337. //ZOID
  1338.         gi.configstring (CS_PLAYERSKINS+playernum, va("%s\\%s", ent->client->pers.netname, s) );
  1339.  
  1340. //ZOID
  1341.     // set player name field (used in id_state view)
  1342.     gi.configstring (CS_GENERAL+playernum, ent->client->pers.netname);
  1343. //ZOID
  1344.  
  1345.     // fov
  1346.     if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
  1347.     {
  1348.         ent->client->ps.fov = 90;
  1349.     }
  1350.     else
  1351.     {
  1352.         ent->client->ps.fov = atoi(Info_ValueForKey(userinfo, "fov"));
  1353.         if (ent->client->ps.fov < 1)
  1354.             ent->client->ps.fov = 90;
  1355.         else if (ent->client->ps.fov > 160)
  1356.             ent->client->ps.fov = 160;
  1357.     }
  1358.  
  1359.     // handedness
  1360.     s = Info_ValueForKey (userinfo, "hand");
  1361.     if (strlen(s))
  1362.     {
  1363.         ent->client->pers.hand = atoi(s);
  1364.     }
  1365.  
  1366.     // save off the userinfo in case we want to check something later
  1367.     strncpy (ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)-1);
  1368. }
  1369.  
  1370.  
  1371. /*
  1372. ===========
  1373. ClientConnect
  1374.  
  1375. Called when a player begins connecting to the server.
  1376. The game can refuse entrance to a client by returning false.
  1377. If the client is allowed, the connection process will continue
  1378. and eventually get to ClientBegin()
  1379. Changing levels will NOT cause this to be called again, but
  1380. loadgames will.
  1381. ============
  1382. */
  1383. qboolean ClientConnect (edict_t *ent, char *userinfo)
  1384. {
  1385.     char    *value;
  1386.  
  1387.     // check to see if they are on the banned IP list
  1388.     value = Info_ValueForKey (userinfo, "ip");
  1389.     if (SV_FilterPacket(value)) {
  1390.         Info_SetValueForKey(userinfo, "rejmsg", "Banned.");
  1391.         return false;
  1392.     }
  1393.  
  1394.  
  1395.     // check for a password
  1396.     value = Info_ValueForKey (userinfo, "password");
  1397.     if (*password->string && strcmp(password->string, "none") && 
  1398.         strcmp(password->string, value)) {
  1399.         Info_SetValueForKey(userinfo, "rejmsg", "Password required or incorrect.");
  1400.         return false;
  1401.     }
  1402.  
  1403.     // they can connect
  1404.     ent->client = game.clients + (ent - g_edicts - 1);
  1405.  
  1406.     // if there is already a body waiting for us (a loadgame), just
  1407.     // take it, otherwise spawn one from scratch
  1408.     if (ent->inuse == false)
  1409.     {
  1410.         // clear the respawning variables
  1411. //ZOID -- force team join
  1412.         ent->client->resp.ctf_team = -1;
  1413.         ent->client->resp.id_state = true; 
  1414. //ZOID
  1415.         InitClientResp (ent->client);
  1416.         if (!game.autosaved || !ent->client->pers.weapon)
  1417.             InitClientPersistant (ent->client);
  1418.     }
  1419.  
  1420.     ClientUserinfoChanged (ent, userinfo);
  1421.  
  1422.     if (game.maxclients > 1)
  1423.         gi.dprintf ("%s connected\n", ent->client->pers.netname);
  1424.  
  1425.     ent->client->pers.connected = true;
  1426.     return true;
  1427. }
  1428.  
  1429. /*
  1430. ===========
  1431. ClientDisconnect
  1432.  
  1433. Called when a player drops from the server.
  1434. Will not be called between levels.
  1435. ============
  1436. */
  1437. void ClientDisconnect (edict_t *ent)
  1438. {
  1439.     int        playernum;
  1440.  
  1441.     if (!ent->client)
  1442.         return;
  1443.  
  1444.     gi.bprintf (PRINT_HIGH, "%s disconnected\n", ent->client->pers.netname);
  1445.  
  1446. //ZOID
  1447.     CTFDeadDropFlag(ent);
  1448.     CTFDeadDropTech(ent);
  1449. //ZOID
  1450.  
  1451.     // send effect
  1452.     gi.WriteByte (svc_muzzleflash);
  1453.     gi.WriteShort (ent-g_edicts);
  1454.     gi.WriteByte (MZ_LOGOUT);
  1455.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1456.  
  1457.     gi.unlinkentity (ent);
  1458.     ent->s.modelindex = 0;
  1459.     ent->solid = SOLID_NOT;
  1460.     ent->inuse = false;
  1461.     ent->classname = "disconnected";
  1462.     ent->client->pers.connected = false;
  1463.  
  1464.     playernum = ent-g_edicts-1;
  1465.     gi.configstring (CS_PLAYERSKINS+playernum, "");
  1466. }
  1467.  
  1468.  
  1469. //==============================================================
  1470.  
  1471.  
  1472. edict_t    *pm_passent;
  1473.  
  1474. // pmove doesn't need to know about passent and contentmask
  1475. trace_t    PM_trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
  1476. {
  1477.     if (pm_passent->health > 0)
  1478.         return gi.trace (start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID);
  1479.     else
  1480.         return gi.trace (start, mins, maxs, end, pm_passent, MASK_DEADSOLID);
  1481. }
  1482.  
  1483. unsigned CheckBlock (void *b, int c)
  1484. {
  1485.     int    v,i;
  1486.     v = 0;
  1487.     for (i=0 ; i<c ; i++)
  1488.         v+= ((byte *)b)[i];
  1489.     return v;
  1490. }
  1491. void PrintPmove (pmove_t *pm)
  1492. {
  1493.     unsigned    c1, c2;
  1494.  
  1495.     c1 = CheckBlock (&pm->s, sizeof(pm->s));
  1496.     c2 = CheckBlock (&pm->cmd, sizeof(pm->cmd));
  1497.     Com_Printf ("sv %3i:%i %i\n", pm->cmd.impulse, c1, c2);
  1498. }
  1499.  
  1500. /*
  1501. ==============
  1502. ClientThink
  1503.  
  1504. This will be called once for each client frame, which will
  1505. usually be a couple times for each server frame.
  1506. ==============
  1507. */
  1508. void ClientThink (edict_t *ent, usercmd_t *ucmd)
  1509. {
  1510.     gclient_t    *client;
  1511.     edict_t    *other;
  1512.     int        i, j;
  1513.     pmove_t    pm;
  1514.  
  1515.     level.current_entity = ent;
  1516.     client = ent->client;
  1517.  
  1518.     if (level.intermissiontime)
  1519.     {
  1520.         client->ps.pmove.pm_type = PM_FREEZE;
  1521.         // can exit intermission after five seconds
  1522.         if (level.time > level.intermissiontime + 5.0 
  1523.             && (ucmd->buttons & BUTTON_ANY) )
  1524.             level.exitintermission = true;
  1525.         return;
  1526.     }
  1527.  
  1528.     pm_passent = ent;
  1529.  
  1530. //ZOID
  1531.     if (ent->client->chase_target) {
  1532.         client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
  1533.         client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
  1534.         client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
  1535.         return;
  1536.     }
  1537. //ZOID
  1538.  
  1539.     // set up for pmove
  1540.     memset (&pm, 0, sizeof(pm));
  1541.  
  1542.     if (ent->movetype == MOVETYPE_NOCLIP)
  1543.         client->ps.pmove.pm_type = PM_SPECTATOR;
  1544.     else if (ent->s.modelindex != 255)
  1545.         client->ps.pmove.pm_type = PM_GIB;
  1546.     else if (ent->deadflag)
  1547.         client->ps.pmove.pm_type = PM_DEAD;
  1548.     else
  1549.         client->ps.pmove.pm_type = PM_NORMAL;
  1550.  
  1551.     client->ps.pmove.gravity = sv_gravity->value;
  1552.     pm.s = client->ps.pmove;
  1553.  
  1554.     for (i=0 ; i<3 ; i++)
  1555.     {
  1556.         pm.s.origin[i] = ent->s.origin[i]*8;
  1557.         pm.s.velocity[i] = ent->velocity[i]*8;
  1558.     }
  1559.  
  1560.     if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s)))
  1561.     {
  1562.         pm.snapinitial = true;
  1563. //        gi.dprintf ("pmove changed!\n");
  1564.     }
  1565.  
  1566.     pm.cmd = *ucmd;
  1567.  
  1568.     pm.trace = PM_trace;    // adds default parms
  1569.     pm.pointcontents = gi.pointcontents;
  1570.  
  1571.     // perform a pmove
  1572.     gi.Pmove (&pm);
  1573.  
  1574.     // save results of pmove
  1575.     client->ps.pmove = pm.s;
  1576.     client->old_pmove = pm.s;
  1577.  
  1578.     for (i=0 ; i<3 ; i++)
  1579.     {
  1580.         ent->s.origin[i] = pm.s.origin[i]*0.125;
  1581.         ent->velocity[i] = pm.s.velocity[i]*0.125;
  1582.     }
  1583.  
  1584.     VectorCopy (pm.mins, ent->mins);
  1585.     VectorCopy (pm.maxs, ent->maxs);
  1586.  
  1587.     client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]);
  1588.     client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]);
  1589.     client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]);
  1590.  
  1591.     if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0))
  1592.     {
  1593.         gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0);
  1594.         PlayerNoise(ent, ent->s.origin, PNOISE_SELF);
  1595.     }
  1596.  
  1597.     ent->viewheight = pm.viewheight;
  1598.     ent->waterlevel = pm.waterlevel;
  1599.     ent->watertype = pm.watertype;
  1600.     ent->groundentity = pm.groundentity;
  1601.     if (pm.groundentity)
  1602.         ent->groundentity_linkcount = pm.groundentity->linkcount;
  1603.  
  1604.     if (ent->deadflag)
  1605.     {
  1606.         client->ps.viewangles[ROLL] = 40;
  1607.         client->ps.viewangles[PITCH] = -15;
  1608.         client->ps.viewangles[YAW] = client->killer_yaw;
  1609.     }
  1610.     else
  1611.     {
  1612.         VectorCopy (pm.viewangles, client->v_angle);
  1613.         VectorCopy (pm.viewangles, client->ps.viewangles);
  1614.     }
  1615.  
  1616. //ZOID
  1617.     if (client->ctf_grapple)
  1618.         CTFGrapplePull(client->ctf_grapple);
  1619. //ZOID
  1620.  
  1621.     gi.linkentity (ent);
  1622.  
  1623.     if (ent->movetype != MOVETYPE_NOCLIP)
  1624.         G_TouchTriggers (ent);
  1625.  
  1626.     // touch other objects
  1627.     for (i=0 ; i<pm.numtouch ; i++)
  1628.     {
  1629.         other = pm.touchents[i];
  1630.         for (j=0 ; j<i ; j++)
  1631.             if (pm.touchents[j] == other)
  1632.                 break;
  1633.         if (j != i)
  1634.             continue;    // duplicated
  1635.         if (!other->touch)
  1636.             continue;
  1637.         other->touch (other, ent, NULL, NULL);
  1638.     }
  1639.  
  1640.  
  1641.     client->oldbuttons = client->buttons;
  1642.     client->buttons = ucmd->buttons;
  1643.     client->latched_buttons |= client->buttons & ~client->oldbuttons;
  1644.  
  1645.     // save light level the player is standing on for
  1646.     // monster sighting AI
  1647.     ent->light_level = ucmd->lightlevel;
  1648.  
  1649.     // fire weapon from final position if needed
  1650.     if (client->latched_buttons & BUTTON_ATTACK
  1651. //ZOID
  1652.         && ent->movetype != MOVETYPE_NOCLIP
  1653. //ZOID
  1654.         )
  1655.     {
  1656.         if (!client->weapon_thunk)
  1657.         {
  1658.             client->weapon_thunk = true;
  1659.             Think_Weapon (ent);
  1660.         }
  1661.     }
  1662.  
  1663. //ZOID
  1664. //regen tech
  1665.     CTFApplyRegeneration(ent);
  1666. //ZOID
  1667.  
  1668. //ZOID
  1669.     for (i = 1; i <= maxclients->value; i++) {
  1670.         other = g_edicts + i;
  1671.         if (other->inuse && other->client->chase_target == ent)
  1672.             UpdateChaseCam(other);
  1673.     }
  1674.  
  1675.     if (client->menudirty && client->menutime <= level.time) {
  1676.         PMenu_Do_Update(ent);
  1677.         gi.unicast (ent, true);
  1678.         client->menutime = level.time;
  1679.         client->menudirty = false;
  1680.     }
  1681. //ZOID
  1682. }
  1683.  
  1684.  
  1685. /*
  1686. ==============
  1687. ClientBeginServerFrame
  1688.  
  1689. This will be called once for each server frame, before running
  1690. any other entities in the world.
  1691. ==============
  1692. */
  1693. void ClientBeginServerFrame (edict_t *ent)
  1694. {
  1695.     gclient_t    *client;
  1696.     int            buttonMask;
  1697.  
  1698.     if (level.intermissiontime)
  1699.         return;
  1700.  
  1701.     client = ent->client;
  1702.  
  1703.     // run weapon animations if it hasn't been done by a ucmd_t
  1704.     if (!client->weapon_thunk
  1705. //ZOID
  1706.         && ent->movetype != MOVETYPE_NOCLIP
  1707. //ZOID
  1708.         )
  1709.         Think_Weapon (ent);
  1710.     else
  1711.         client->weapon_thunk = false;
  1712.  
  1713.     if (ent->deadflag)
  1714.     {
  1715.         // wait for any button just going down
  1716.         if ( level.time > client->respawn_time)
  1717.         {
  1718.             // in deathmatch, only wait for attack button
  1719.             if (deathmatch->value)
  1720.                 buttonMask = BUTTON_ATTACK;
  1721.             else
  1722.                 buttonMask = -1;
  1723.  
  1724.             if ( ( client->latched_buttons & buttonMask ) ||
  1725.                 (deathmatch->value && ((int)dmflags->value & DF_FORCE_RESPAWN) ) ||
  1726.                 CTFMatchOn())
  1727.             {
  1728.                 respawn(ent);
  1729.                 client->latched_buttons = 0;
  1730.             }
  1731.         }
  1732.         return;
  1733.     }
  1734.  
  1735.     // add player trail so monsters can follow
  1736.     if (!deathmatch->value)
  1737.         if (!visible (ent, PlayerTrail_LastSpot() ) )
  1738.             PlayerTrail_Add (ent->s.old_origin);
  1739.  
  1740.     client->latched_buttons = 0;
  1741. }
  1742.